{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "oL9KopJirB2g"
      },
      "source": [
        "##### Copyright 2018 The TensorFlow Authors."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "SKaX3Hd3ra6C"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "AXH1bmUctMld"
      },
      "source": [
        "# String Unicode\n",
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://www.tensorflow.org/tutorials/load_data/unicode\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\" />Lihat di TensorFlow.org</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/id/tutorials/load_data/unicode.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\" />Jalankan di Google Colab</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://github.com/tensorflow/docs-l10n/blob/master/site/id/tutorials/load_data/unicode.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\" />Liat source di GitHub</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a href=\"https://storage.googleapis.com/tensorflow_docs/docs-l10n/site/id/tutorials/load_data/unicode.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\" />Unduh notebook</a>\n",
        "  </td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "psr4plTw1HKs"
      },
      "source": [
        "## Pengenalan\n",
        "Model yang memproses bahasa alami (*natural language*) sering menangani bahasa dan simbol/karakter yang berbeda-beda. *Unicode* adalah standar sistem pengkodean yang digunakan untuk mewakili simbol/karakter dari hampir semua bahasa. Setiap karakter dikodekan menggunakan integer unik [*code point*] (https://en.wikipedia.org/wiki/Code_point) antara `0` dan` 0x10FFFF`. Sebuah *Unicode string* adalah rangkaian dari nol atau lebih *code point*.\n",
        "\n",
        "Tutorial ini, menunjukkan bagaimana cara merepresentasikan string Unicode di TensorFlow dan memanipulasinya menggunakan Unicode yang ekuivalen dengan standar operasi string. Cara ini, bertujuan untuk memisahkan *Unicode strings* menjadi beberapa token berdasarkan kata-kata yang dideteksi."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "OIKHl5Lvn4gh"
      },
      "outputs": [],
      "source": [
        "from __future__ import absolute_import, division, print_function, unicode_literals\n",
        "\n",
        "try:\n",
        "  # %tensorflow_version hanya ada di Colab.\n",
        "  %tensorflow_version 2.x\n",
        "except Exception:\n",
        "  pass\n",
        "import tensorflow as tf"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "oIbGuviXT4mm"
      },
      "source": [
        "## Tipe data `tf.string`\n",
        "\n",
        "TensorFlow `tf.string`` dtype` memungkinkan Anda membangun tensor dari beberapa byte string.\n",
        "*Unicode strings* secara default, menggunakan utf-8."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "3yo-Qv6ntaFr"
      },
      "outputs": [],
      "source": [
        "tf.constant(u\"Thanks 😊\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "En6bmWUQsOFx"
      },
      "source": [
        "Tensor `tf.string` dapat menampung string byte dengan panjang yang berbeda-beda karena string byte diperlakukan sebagai unit atom. Panjang string tidak masuk dalam dimensi tensor."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "eyINCmTztyyS"
      },
      "outputs": [],
      "source": [
        "tf.constant([u\"You're\", u\"welcome!\"]).shape"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "25KrVcGjaksl"
      },
      "source": [
        "Catatan: Saat menggunakan python untuk membangun string, penanganan unicode berbeda antara v2 dan v3. Dalam v2, *unicode strings* ditunjukkan oleh awalan \"u\", seperti di atas. Di v3, strings adalah unicode yang terkodekan secara default."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3P8V_Z5WDhmg"
      },
      "source": [
        "## Mewakili Unicode\n",
        "\n",
        "Ada dua cara standar untuk menunjukan string Unicode di TensorFlow:\n",
        "\n",
        "* `string` scalar - di mana urutan code points dikodekan menggunakan  [character encoding](https://en.wikipedia.org/wiki/Character_encoding).\n",
        "* `int32` vector - di mana setiap posisi berisi satu code points.\n",
        "\n",
        "Misalnya, tiga nilai berikut semuanya mewakili Unicode string `\"语言处理\"` (yang berarti \"pemrosesan bahasa\" dalam bahasa Cina):"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "cjQIkfJWvC_u"
      },
      "outputs": [],
      "source": [
        "# Unicode string, ditunjukan sebagai string scalar yang dikodekan menggunakan format UTF-8\n",
        "text_utf8 = tf.constant(u\"语言处理\")\n",
        "text_utf8"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "yQqcUECcvF2r"
      },
      "outputs": [],
      "source": [
        "# Unicode string, ditunjukan sebagai string scalar yang dikodekan menggunakan format UTF-16-BE\n",
        "text_utf16be = tf.constant(u\"语言处理\".encode(\"UTF-16-BE\"))\n",
        "text_utf16be"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ExdBr1t7vMuS"
      },
      "outputs": [],
      "source": [
        "# Unicode string, ditunjukan sebagai sebuah vektor dalam code point Unicode.\n",
        "text_chars = tf.constant([ord(char) for char in u\"语言处理\"])\n",
        "text_chars"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7EI5HMPZiBDy"
      },
      "source": [
        "### Konversi di antara representasi\n",
        "\n",
        "TensorFlow menyediakan operasi untuk mengkonversi vektor, skalar, atau format :\n",
        "\n",
        "* `tf.strings.unicode_decode`: Mengonversi skalar string yang dikodekan ke vektor.\n",
        "* `tf.strings.unicode_encode`: Mengonversi vektor ke skalar string yang dikodekan.\n",
        "* `tf.strings.unicode_transcode`: Mengonversi skalar string yang dikodekan ke format pengkodean yang berbeda."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "qb-UQ_oLpAJg"
      },
      "outputs": [],
      "source": [
        "tf.strings.unicode_decode(text_utf8,\n",
        "                          input_encoding='UTF-8')"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "kEBUcunnp-9n"
      },
      "outputs": [],
      "source": [
        "tf.strings.unicode_encode(text_chars,\n",
        "                          output_encoding='UTF-8')"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "0MLhWcLZrph-"
      },
      "outputs": [],
      "source": [
        "tf.strings.unicode_transcode(text_utf8,\n",
        "                             input_encoding='UTF8',\n",
        "                             output_encoding='UTF-16-BE')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "KvW-LK79ZiP8"
      },
      "source": [
        "### Dimensi batch\n",
        "\n",
        "Saat mendekode beberapa string, jumlah karakter dalam setiap string mungkin tidak sama. Hasil returnnya adalah [`tf.RaggedTensor`](../../guide/ragged_tensor.ipynb), di mana panjang dimensi bervariasi ,tergantung pada jumlah karakter di setiap string:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "N2jVzPymr_Mm"
      },
      "outputs": [],
      "source": [
        "# A batch of Unicode strings, each represented as a UTF8-encoded string.\n",
        "batch_utf8 = [s.encode('UTF-8') for s in\n",
        "              [u'hÃllo',  u'What is the weather tomorrow',  u'Göödnight', u'😊']]\n",
        "batch_chars_ragged = tf.strings.unicode_decode(batch_utf8,\n",
        "                                               input_encoding='UTF-8')\n",
        "for sentence_chars in batch_chars_ragged.to_list():\n",
        "  print(sentence_chars)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "d5fVzKhkCkPw"
      },
      "source": [
        "Anda dapat menggunakan `tf.RaggedTensor` ini secara langsung, atau mengonversinya menjadi` tf.Tensor` dengan padding atau `tf.SparseTensor` menggunakan metode` tf.RaggedTensor.to_tensor` dan `tf.RaggedTensor.to_sparse`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "yz17yeSMsUid"
      },
      "outputs": [],
      "source": [
        "batch_chars_padded = batch_chars_ragged.to_tensor(default_value=-1)\n",
        "print(batch_chars_padded.numpy())"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "kBjsPQp3rhfm"
      },
      "outputs": [],
      "source": [
        "batch_chars_sparse = batch_chars_ragged.to_sparse()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "RiCdAklZQkU0"
      },
      "source": [
        "Saat mengkodekan beberapa string dengan panjang yang sama, `tf.Tensor` dapat digunakan sebagai input:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "_lP62YUAwjK9"
      },
      "outputs": [],
      "source": [
        "tf.strings.unicode_encode([[99, 97, 116], [100, 111, 103], [ 99, 111, 119]],\n",
        "                          output_encoding='UTF-8')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1S0D5Dk8H6qR"
      },
      "source": [
        "Saat mengkodekan beberapa string dengan panjang yang bervariasi, `tf.RaggedTensor` dapat digunakan sebagai input:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "d7GtOtrltaMl"
      },
      "outputs": [],
      "source": [
        "tf.strings.unicode_encode(batch_chars_ragged, output_encoding='UTF-8')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "mR2ufddlhEtR"
      },
      "source": [
        "Jika Anda memiliki tensor dengan beberapa string dalam format padded atau sparse, konversikan ke `tf.RaggedTensor` sebelum memanggil` unicode_encode`:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "R2bYCYl0u-Ue"
      },
      "outputs": [],
      "source": [
        "tf.strings.unicode_encode(\n",
        "    tf.RaggedTensor.from_sparse(batch_chars_sparse),\n",
        "    output_encoding='UTF-8')"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "UlV2znh_u_zm"
      },
      "outputs": [],
      "source": [
        "tf.strings.unicode_encode(\n",
        "    tf.RaggedTensor.from_tensor(batch_chars_padded, padding=-1),\n",
        "    output_encoding='UTF-8')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hQOOGkscvDpc"
      },
      "source": [
        "## Operasi Unicode "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "UCA60DhAawl5"
      },
      "source": [
        "### Panjang karakter\n",
        "\n",
        "Operasi `tf.strings.length` memiliki parameter` unit`, yang menunjukkan cara/format karakter harus dikodekan. `unit` secara default menjadi` \"BYTE\" `, tetapi dapat disetel ke nilai lain, seperti` \"UTF8_CHAR\" `atau` \"UTF16_CHAR\" `, untuk menentukan jumlah code point Unicode di setiap` string` yang dikodekan."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "1ZzMe59mvLHr"
      },
      "outputs": [],
      "source": [
        "# Perhatikan bahwa karakter terakhir membutuhkan 4 byte dalam UTF8.\n",
        "thanks = u'Thanks 😊'.encode('UTF-8')\n",
        "num_bytes = tf.strings.length(thanks).numpy()\n",
        "num_chars = tf.strings.length(thanks, unit='UTF8_CHAR').numpy()\n",
        "print('{} bytes; {} UTF-8 characters'.format(num_bytes, num_chars))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "zd9ApRY-mHhU"
      },
      "source": [
        "### Substring karakter\n",
        "\n",
        "Hampir sama, operasi `tf.strings.substr` terdapat parameter\" `unit`\", dan digunakan untuk menentukan jenis offset apa yang ada dalam parameter \"` pos` \"dan\" `len`\"."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "WlWRLV-4xWYq"
      },
      "outputs": [],
      "source": [
        "# default: unit='BYTE'. With len=1, we return a single byte.\n",
        "# default: unit='BYTE'. Dengan len=1, menunjukan 1  byte.\n",
        "tf.strings.substr(thanks, pos=7, len=1).numpy()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "JfNUVDPwxkCS"
      },
      "outputs": [],
      "source": [
        "# Specifying unit='UTF8_CHAR', we return a single character, which in this case\n",
        "# is 4 bytes.\n",
        "# Dengan mengatur unit='UTF8_CHAR', kita menunjukan 1 karakter, dengan panjang\n",
        "# 4 bytes.\n",
        "print(tf.strings.substr(thanks, pos=7, len=1, unit='UTF8_CHAR').numpy())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "lpAzc5OexEVT"
      },
      "source": [
        "### Memecah Unicode Strings\n",
        "\n",
        "Operasi `tf.strings.unicode_split` memecah string unicode menjadi substring karakter:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "dDjkh5G1ejMt"
      },
      "outputs": [],
      "source": [
        "tf.strings.unicode_split(thanks, 'UTF-8').numpy()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "UQcVMlCUP_Iw"
      },
      "source": [
        "### Byte offset untuk karakter\n",
        "\n",
        "Untuk menyelaraskan tensor karakter yang dihasilkan oleh `tf.strings.unicode_decode` dengan string asli, penting untuk mengetahui offset pada setiap awal karakter. Metode `tf.strings.unicode_decode_with_offsets` mirip dengan` unicode_decode`, tapi metode ini me-return tensor kedua yang berisi offset awal setiap karakter."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Cug7cmwYdowd"
      },
      "outputs": [],
      "source": [
        "codepoints, offsets = tf.strings.unicode_decode_with_offsets(u\"🎈🎉🎊\", 'UTF-8')\n",
        "\n",
        "for (codepoint, offset) in zip(codepoints.numpy(), offsets.numpy()):\n",
        "  print(\"At byte offset {}: codepoint {}\".format(offset, codepoint))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "2ZnCNxOvx66T"
      },
      "source": [
        "## Script Unicode"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "dHxCpyxDW4qN"
      },
      "source": [
        "Setiap code point Unicode, merupakan milik satu kumpulan codepoint yang dikenal sebagai [script](https://en.wikipedia.org/wiki/Script_%28Unicode%29). Script dari sebuah karakter sangat membantu dalam menentukan bahasa yang mungkin digunakan karakter tersebut. Misalnya, mengetahui bahwa 'Б' dalam script Cyrillic menunjukkan bahwa teks modern yang mengandung karakter tersebut kemungkinan berasal dari bahasa Slavik seperti Rusia atau Ukraina.\n",
        "\n",
        "TensorFlow menyediakan operasi `tf.strings.unicode_script` untuk menentukan script mana yang digunakan oleh code point tertentu. Script code yang bernilai `int32` sesuai dengan nilai [International Components for\n",
        "Unicode](http://site.icu-project.org/home) (ICU) [`UScriptCode`](http://icu-project.org/apiref/icu4c/uscript_8h.html)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "K7DeYHrRyFPy"
      },
      "outputs": [],
      "source": [
        "uscript = tf.strings.unicode_script([33464, 1041])  # ['芸', 'Б']\n",
        "\n",
        "print(uscript.numpy())  # [17, 8] == [USCRIPT_HAN, USCRIPT_CYRILLIC]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "2fW992a1lIY6"
      },
      "source": [
        "The `tf.strings.unicode_script` operation can also be applied to multidimensional `tf.Tensor`s or `tf.RaggedTensor`s of codepoints:"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ixb2RSNTApaE"
      },
      "source": [
        "Operasi `tf.strings.unicode_script` juga dapat diterapkan ke` tf.Tensor` atau `tf.RaggedTensor` dari codepoint:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "uR7b8meLlFnp"
      },
      "outputs": [],
      "source": [
        "print(tf.strings.unicode_script(batch_chars_ragged))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "JzQAYTpoxK_n"
      },
      "source": [
        "## Contoh: Segmentasi sederhana\n",
        "\n",
        "Segmentasi adalah memisahkan teks menjadi satuan kata-kata. Segmentasi mudah dilakukan ketika karakter spasi digunakan untuk memisahkan antar kata, tetapi beberapa bahasa (seperti Cina dan Jepang) tidak menggunakan spasi, dan beberapa bahasa (seperti Jerman) mengandung gabungan yang harus dipecah untuk menganalisis artinya. Dalam teks web, berbagai bahasa dan script sering dicampur bersama, seperti dalam \"NY 株 価\" (Bursa Saham New York).\n",
        "\n",
        "Kita dapat melakukan segmentasi yang sangat kasar (tanpa menerapkan model ML) dengan menggunakan perubahan nilai pada script untuk memperkirakan pembatas kata. Cara ini dapat digunakan untuk string seperti contoh \"NY 株 価\" di atas. Cara ini juga dapat digunakan untuk sebagian besar bahasa yang menggunakan spasi, karena karakter spasi dari berbagai script semuanya diklasifikasikan sebagai USCRIPT_COMMON, kode skrip khusus yang berbeda dengan teks aktual apa pun."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "grsvFiC4BoPb"
      },
      "outputs": [],
      "source": [
        "# dtype: string; shape: [num_sentences]\n",
        "#\n",
        "# sebuah kalimat untuk contoh.  Silakan diganti menggunakan bahasa lain untuk mencoba input yang berbeda!\n",
        "sentence_texts = [u'Hello, world.', u'世界こんにちは']"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "CapnbShuGU8i"
      },
      "source": [
        "First, we decode the sentences into character codepoints, and find the script identifeir for each character."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "mAvpayZKbWvn"
      },
      "source": [
        "Pertama, kita menkodedan kalimat menjadi codepoints karakter, dan menemukan pengidentifikasi script untuk setiap karakter."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ReQVcDQh1MB8"
      },
      "outputs": [],
      "source": [
        "# dtype: int32; shape: [num_sentences, (num_chars_per_sentence)]\n",
        "#\n",
        "# sentence_char_codepoint[i, j] adalah codepoint untuk karakter urutan ke j pada\n",
        "# kalimat urutan ke i.\n",
        "sentence_char_codepoint = tf.strings.unicode_decode(sentence_texts, 'UTF-8')\n",
        "print(sentence_char_codepoint)\n",
        "\n",
        "# dtype: int32; shape: [num_sentences, (num_chars_per_sentence)]\n",
        "#\n",
        "# sentence_char_scripts[i, j] adalah unicode script untuk karakter urutan ke j pada\n",
        "# kalimat urutan ke i.\n",
        "sentence_char_script = tf.strings.unicode_script(sentence_char_codepoint)\n",
        "print(sentence_char_script)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "4JZxE4Z2RZCQ"
      },
      "source": [
        "Selanjutnya, kita menggunakan pengidentifikasi script tersebut untuk menentukan di mana batas katanya. Kita menambahkan batas kata di awal setiap kalimat, dan untuk setiap karakter yang scripnya berbeda dari karakter sebelumnya:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "7v5W6MOr1Rlc"
      },
      "outputs": [],
      "source": [
        "# dtype: bool; shape: [num_sentences, (num_chars_per_sentence)]\n",
        "#\n",
        "# sentence_char_starts_word[i, j] bernilai True jika karakter urutan ke j dalam\n",
        "# kalimat urutan ke i adalah awal dari sebuah kata.\n",
        "sentence_char_starts_word = tf.concat(\n",
        "    [tf.fill([sentence_char_script.nrows(), 1], True),\n",
        "     tf.not_equal(sentence_char_script[:, 1:], sentence_char_script[:, :-1])],\n",
        "    axis=1)\n",
        "\n",
        "# dtype: int64; shape: [num_words]\n",
        "#\n",
        "# word_starts[i] adalah index dari karakter yang merupakan awal dari urutan kata ke i (dalam\n",
        "# daftar kata dari kalimat).\n",
        "word_starts = tf.squeeze(tf.where(sentence_char_starts_word.values), axis=1)\n",
        "print(word_starts)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "LAwh-1QkGuC9"
      },
      "source": [
        "Kita kemudian dapat menggunakan *start offsets* tersebut untuk membangun sebuah `RaggedTensor` yang terdiri atas list kata-kata dari seluruh batch:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "bNiA1O_eBBCL"
      },
      "outputs": [],
      "source": [
        "# dtype: int32; shape: [num_words, (num_chars_per_word)]\n",
        "#\n",
        "# word_char_codepoint[i, j] adalah codepoint untuk urutan karakter ke j dalam\n",
        "# urutan kata ke i.\n",
        "word_char_codepoint = tf.RaggedTensor.from_row_starts(\n",
        "    values=sentence_char_codepoint.values,\n",
        "    row_starts=word_starts)\n",
        "print(word_char_codepoint)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "zTxNINTryOX0"
      },
      "source": [
        "Dan akhirnya, kita dapat mengelompokkan codepoint kata `RaggedTensor` kembali ke kalimat:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "NCfwcqLSEjZb"
      },
      "outputs": [],
      "source": [
        "# dtype: int64; shape: [num_sentences]\n",
        "#\n",
        "# sentence_num_words[i] adalah jumlah kata dalam urutan kalimat ke-i.\n",
        "sentence_num_words = tf.reduce_sum(\n",
        "    tf.cast(sentence_char_starts_word, tf.int64),\n",
        "    axis=1)\n",
        "\n",
        "# dtype: int32; shape: [num_sentences, (num_words_per_sentence), (num_chars_per_word)]\n",
        "#\n",
        "# sentence_word_char_codepoint[i, j, k] adalah codepoint untuk urutan karakter ke k\n",
        "# dalam urutan kata ke j dalam urutan kaliman ke i.\n",
        "sentence_word_char_codepoint = tf.RaggedTensor.from_row_lengths(\n",
        "    values=word_char_codepoint,\n",
        "    row_lengths=sentence_num_words)\n",
        "print(sentence_word_char_codepoint)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "o-KFFBfSzC0a"
      },
      "source": [
        "Untuk membuat hasil akhir lebih mudah dibaca, kita dapat mengkodekannnya kembali ke string UTF-8:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "HSivquOgFr3C"
      },
      "outputs": [],
      "source": [
        "tf.strings.unicode_encode(sentence_word_char_codepoint, 'UTF-8').to_list()"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [
        "oL9KopJirB2g"
      ],
      "name": "unicode.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
